class EulerSieve {
public:

    EulerSieve(const EulerSieve&) = delete;
    EulerSieve& operator=(const EulerSieve&) = delete;

    explicit EulerSieve(int max_number) {
        ValidateInput(max_number);
        InitializeTables(max_number);
        SieveProcess(max_number);
    }


    const std::vector<int>& GetPrimes() const noexcept {
        return primes_;
    }


    int GetEulerPhi(int number) const {
        if(ValidateNumber(number) == 0) {
            return euler_phi_[number];
        }
        return -1;
    }


    int GetMinPrimeFactor(int number) const {
        if(ValidateNumber(number) == 0) {
            return min_prime_factor_[number];
        }
        return -1;
    }

    bool IsPrime(int number) const {
        if(ValidateNumber(number) == -1) {
            return false;
        }
        return (number >= 2) && (min_prime_factor_[number] == number);
    }
private:
    std::vector<int> min_prime_factor_;
    std::vector<int> primes_;
    std::vector<int> euler_phi_;


    static bool ValidateInput(int max_number) {
        if (max_number < 2) {
            return false;
        }
        return true;
    }

    int ValidateNumber(int number) const {
        if (number < 1 || number >= static_cast<int>(euler_phi_.size())) {
            return -1;
        }
        return 0;
    }


    void InitializeTables(int max_number) {
        const int size = max_number + 1;
        min_prime_factor_.assign(size, 0);
        euler_phi_.resize(size);
        primes_.reserve(static_cast<size_t>(1.255 * max_number / log(max_number)));

        euler_phi_[1] = 1;
    }

    void SieveProcess(int max_number) {
        for (int current = 2; current <= max_number; ++current) {
            if (min_prime_factor_[current] == 0) {
                min_prime_factor_[current] = current;
                primes_.push_back(current);
                euler_phi_[current] = current - 1;
            }

            ProcessPrimes(current, max_number);
        }
    }

    void ProcessPrimes(int current, int max_number) {
        for (auto prime : primes_) {
            const int composite = current * prime;
            if (composite > max_number) break;

            min_prime_factor_[composite] = prime;

            if (prime == min_prime_factor_[current]) {
                euler_phi_[composite] = euler_phi_[current] * prime;
                break;
            } else {
                euler_phi_[composite] = euler_phi_[current] * (prime - 1);
            }
        }
    }
};
// EulerSieve sieve(size)